package com.xagent.core;

/**
 * Author: 4ut15m
 * Hook点全局反射入口
 */
public class GlobalEntry {
    private static ThreadLocal<ThreadControl> threadContext = new ThreadLocal<>();

    /**
     * 进入Hook点时，调用该方法
     *
     * @param thisObject 当前调用方法的对象本身，如果调用的是静态方法则为null
     * @param args       当前方法的函数参数，不会为null
     * @param index      索引
     */
    public static void monitorMethodEnter(Object thisObject, Object[] args, int index, String callerClass, String callerMethod, String descriptor) {
        /**
         * 测试代码 start
         * */
        if (callerCheck()) return;
        ThreadControl threadControl = null;
        if (threadContext.get() == null) {
            threadControl = new ThreadControlEnter();
            threadControl.setEnter(true);
            threadContext.set(threadControl);
        } else {
            threadControl = threadContext.get();
            threadControl.setEnter(true);
        }
        try {
            Class<?> aClass = null;
            if (threadControl.getEntryBClass() == null) {
                aClass = Class.forName(Properties.COMMON_ENGINE_ENTRY_CLASS + "B");
                threadControl.setEntryBClass(aClass);
            } else aClass = threadControl.getEntryBClass();
            Entry o = (Entry) aClass.newInstance();
            o.entrance(null, thisObject, args, true, index, callerClass, callerMethod, descriptor);
            threadControl.setEnter(false);
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }


        /**
         * 测试代码 end
         * */

    }

    /**
     * 退出Hook点时，调用该方法
     *
     * @param returnObject 当前方法的返回值
     * @param thisObject   当前调用方法的对象本身，如果调用的是静态方法则为null
     * @param args         当前方法的函数参数，不会为null
     * @param index        索引
     */
    public static void monitorMethodExit(Object returnObject, Object thisObject, Object[] args, int index, String callerClass, String callerMethod, String descriptor) {
        if (callerCheck()) return;
        if (threadContext.get() == null) return;
        ThreadControl threadControl = threadContext.get();
        threadControl.setEnter(true);

        /**
         * 测试代码 start
         * */
        try {
            Class<?> aClass = null;
            if (threadControl.getEntryBClass() == null) {
                aClass = Class.forName(Properties.COMMON_ENGINE_ENTRY_CLASS + "B");
                threadControl.setEntryBClass(aClass);
            } else aClass = threadControl.getEntryBClass();
            Entry o = (Entry) aClass.newInstance();
            o.entrance(returnObject, thisObject, args, false, index, callerClass, callerMethod, descriptor);
            threadControl.setEnter(false);
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        /**
         * 测试代码 end
         * */
    }

    public static boolean callerCheck() {
        if (threadContext.get() == null) {
            return false;
        }
        ThreadControl threadControl = threadContext.get();
        if (threadControl.isEnter()) {
            return true;
        }

//        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
//        StackTraceElement getStackMethod = stackTrace[0]; // getStackTrace
//        StackTraceElement currentMethod = stackTrace[1];    // callerCheck
//        StackTraceElement preMethod = stackTrace[2]; // Entry or exit
//        StackTraceElement calleeMethod = stackTrace[3]; // Callee
//        StackTraceElement callerMethod = stackTrace[4]; // Caller
//        System.out.println(callerMethod);
//        if (callerMethod.getClassName().startsWith("com.xagent.")) return true;
//        if (callerMethod.getClassName().startsWith("org.springframework")) return true;// 过滤spring的方法调用


        return false;
    }

}
